package com.atguigu.gmall.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.atguigu.core.bean.Resp;
import com.atguigu.gmall.pms.entity.BrandEntity;
import com.atguigu.gmall.pms.entity.CategoryEntity;
import com.atguigu.gmall.pms.entity.ProductAttrValueEntity;
import com.atguigu.gmall.pms.entity.SkuInfoEntity;
import com.atguigu.gmall.pms.feign.GmallPmsApi;
import com.atguigu.gmall.search.service.SearchService;
import com.atguigu.gmall.search.vo.*;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.atguigu.gmall.wms.feign.GmallWmsApi;
import io.searchbox.client.JestClient;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import io.searchbox.core.search.aggregation.ChildrenAggregation;
import io.searchbox.core.search.aggregation.MetricAggregation;
import io.searchbox.core.search.aggregation.TermsAggregation;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private JestClient jestClient;

    @Autowired
    private GmallPmsApi gmallPmsFeign;

    @Autowired
    private GmallWmsApi gmallWmsFeign;


    /**
     * 通过MQ获取新增商品，保存到ES
     * @param spuId
     */
    @Override
    public void createIndex(Long spuId) {

        Resp<List<SkuInfoEntity>> skuInfoResp = this.gmallPmsFeign.querySkuBySpuId(spuId);
        List<SkuInfoEntity> skuInfoEntities = skuInfoResp.getData();
        if (!CollectionUtils.isEmpty(skuInfoEntities)) {
            skuInfoEntities.forEach(skuInfoEntity -> {
                GoodsVO goodsVO = new GoodsVO();
                goodsVO.setId(skuInfoEntity.getSkuId());
                goodsVO.setName(skuInfoEntity.getSkuName());
                goodsVO.setPic(skuInfoEntity.getSkuDefaultImg());
                goodsVO.setPrice(skuInfoEntity.getPrice());
                goodsVO.setSale(0); // 销量，数据库暂没设计
                goodsVO.setSort(0);
                // 设置库存
                Resp<List<WareSkuEntity>> wareSkuResp = this.gmallWmsFeign.queryWareSkuBySkuId(skuInfoEntity.getSkuId());
                List<WareSkuEntity> wareSkuEntities = wareSkuResp.getData();
                if (!CollectionUtils.isEmpty(wareSkuEntities)) {
                    long sum = wareSkuEntities.stream().mapToLong(WareSkuEntity::getSkuId).sum();
                    goodsVO.setStock(sum);
                }
                // 设置品牌
                goodsVO.setBrandId(skuInfoEntity.getBrandId());
                if (skuInfoEntity.getBrandId() != null) {
                    Resp<BrandEntity> brandEntityResp = this.gmallPmsFeign.info(skuInfoEntity.getBrandId());
                    if (brandEntityResp.getData() != null) {
                        goodsVO.setBrandName(brandEntityResp.getData().getName());
                    }
                }
                // 设置分类
                goodsVO.setProductCategoryId(skuInfoEntity.getCatalogId());
                if (skuInfoEntity.getCatalogId() != null) {
                    Resp<CategoryEntity> categoryEntityResp = this.gmallPmsFeign.catInfo(skuInfoEntity.getCatalogId());
                    if (categoryEntityResp.getData() != null) {
                        goodsVO.setProductCategoryName(categoryEntityResp.getData().getName());
                    }
                }
                // 设置搜索的规格属性
                Resp<List<ProductAttrValueEntity>> listResp = this.gmallPmsFeign.querySearchAttrValue(spuId);
                if (!CollectionUtils.isEmpty(listResp.getData())) {
                    List<SpuAttributeValueVO> spuAttributeValueVOS = listResp.getData().stream().map(productAttrValueEntity -> {
                        SpuAttributeValueVO spuAttributeValueVO = new SpuAttributeValueVO();
                        spuAttributeValueVO.setId(productAttrValueEntity.getId());
                        spuAttributeValueVO.setName(productAttrValueEntity.getAttrName());
                        spuAttributeValueVO.setValue(productAttrValueEntity.getAttrValue());
                        spuAttributeValueVO.setProductAttributeId(productAttrValueEntity.getAttrId());
                        spuAttributeValueVO.setSpuId(productAttrValueEntity.getSpuId());
                        return spuAttributeValueVO;
                    }).collect(Collectors.toList());
                    goodsVO.setAttrValueList(spuAttributeValueVOS);
                }
                Index action = new Index.Builder(goodsVO).index("goods").type("info").id(skuInfoEntity.getSkuId().toString()).build();
                try {
                    jestClient.execute(action);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }






    @Override
    public SearchResponse search(SearchParamVO searchParamVO) {
        // 构建查询条件
        String query = buildDslQuery(searchParamVO);
        Search action = new Search.Builder(query).addIndex("goods").addType("info").build();
        try {
            // 执行搜索，获取搜索结果集
            SearchResult result = this.jestClient.execute(action);

            // 解析结果集并响应
            System.out.println(result.toString());
            SearchResponse response = buildSearchResult(result);
            response.setPageNum(searchParamVO.getPageNum()); // 页码
            response.setPageSize(searchParamVO.getPageSize()); // 每页大小
            response.setTotal(result.getTotal()); // 总记录数

            return response;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    private SearchResponse buildSearchResult(SearchResult result) {
        SearchResponse response = new SearchResponse();

        // 1.解析查询的记录结果
        List<SearchResult.Hit<GoodsVO, Void>> hits = result.getHits(GoodsVO.class);
        List<GoodsVO> goodsVOList = hits.stream().map(hit -> hit.source).collect(Collectors.toList());
        response.setProducts(goodsVOList);

        // 2. 解析聚合结果集
        // 筛选属性
        MetricAggregation aggregations = result.getAggregations();
        // 属性子聚合
        ChildrenAggregation attrAgg = aggregations.getChildrenAggregation("attr_agg");
        // 属性id聚合
        TermsAggregation attrIdAgg = attrAgg.getTermsAggregation("attrId_agg");
        // 遍历id聚合桶
        List<SearchResponseAttrVO> attrVOs = attrIdAgg.getBuckets().stream().map(bucket -> {
            SearchResponseAttrVO searchResponseAttrVO = new SearchResponseAttrVO();
            // 属性id
            searchResponseAttrVO.setProductAttributeId(Long.valueOf(bucket.getKeyAsString()));

            // 获取属性名子聚合
            TermsAggregation attrNameAgg = bucket.getTermsAggregation("attrName");
            // 从属性名子聚合中获取属性名
            searchResponseAttrVO.setName(attrNameAgg.getBuckets().get(0).getKeyAsString());

            // 获取属性值子聚合
            TermsAggregation attrValueAgg = bucket.getTermsAggregation("attrValue");
            List<String> values = attrValueAgg.getBuckets().stream().map(b -> b.getKeyAsString()).collect(Collectors.toList());
            // 设置属性值
            searchResponseAttrVO.setValue(values);

            return searchResponseAttrVO;
        }).collect(Collectors.toList());
        response.setAttrs(attrVOs);

        // 封装品牌 TODO
        SearchResponseAttrVO brand = new SearchResponseAttrVO();
        response.setBrand(brand);

        // 封装分类 TODO
        response.setCatelog(new SearchResponseAttrVO());

        return response;
    }

    private String buildDslQuery(SearchParamVO searchParamVO) {
        // 搜索条件构建器，辅助构建dsl语句
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 1.查询及过滤条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        sourceBuilder.query(boolQueryBuilder);
        if (StringUtils.isNotBlank(searchParamVO.getKeyword())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", searchParamVO.getKeyword()).operator(Operator.AND));
        }
        // 属性过滤 2:win10-android-ios   3:4g	   4:5.5
        String[] props = searchParamVO.getProps();
        if (props != null && props.length > 0) {
            for (String prop : props) {
                String[] attr = StringUtils.split(prop, ":");
                if (attr == null || attr.length != 2){
                    continue;
                }
                BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
                boolQuery.must(QueryBuilders.termQuery("attrValueList.productAttributeId", attr[0]));
                boolQuery.must(QueryBuilders.termsQuery("attrValueList.value", attr[1].split("-")));
                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrValueList", boolQuery, ScoreMode.None);
                boolQueryBuilder.filter(nestedQuery);
            }
        }

        // 品牌过滤
        String[] brands = searchParamVO.getBrand();
        if (brands != null && brands.length > 0) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId", brands));
        }

        // 分类过滤
        String[] catelog3 = searchParamVO.getCatelog3();
        if (catelog3 != null && catelog3.length > 0){
            boolQueryBuilder.filter(QueryBuilders.termsQuery("productCategoryId", catelog3));
        }

        // 价格范围过滤
        Integer priceFrom = searchParamVO.getPriceFrom();
        Integer priceTo = searchParamVO.getPriceTo();
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price");
        if (priceFrom != null) {
            rangeQueryBuilder.gte(priceFrom);
        }
        if (priceTo != null) {
            rangeQueryBuilder.lte(priceTo);
        }

        // 2.分页条件
        int start = (searchParamVO.getPageNum() - 1) * searchParamVO.getPageSize();
        sourceBuilder.from(start);
        sourceBuilder.size(searchParamVO.getPageSize());

        // 3.高亮
        if (searchParamVO.getKeyword() != null) {
            sourceBuilder.highlighter(new HighlightBuilder().field("name").preTags("<em style='color: red'>").postTags("<em>"));
        }

        // 4.排序 0：综合排序  1：销量  2：价格 order=1:asc
        String order = searchParamVO.getOrder();
        if (order != null) {
            String[] orderParams = StringUtils.split(order, ":");
            SortOrder sortOrder = StringUtils.equals("asc", orderParams[1]) ? SortOrder.ASC : SortOrder.DESC;
            if (orderParams != null && orderParams.length == 2) {
                switch (orderParams[0]){
                    case "0": sourceBuilder.sort("_source", sortOrder);break;
                    case "1": sourceBuilder.sort("sale", sortOrder);break;
                    case "2": sourceBuilder.sort("price", sortOrder);break;
                    default: break;
                }
            }
        }

        // 5.属性聚合
        //5.1（嵌套聚合）
        NestedAggregationBuilder nestedAgg = AggregationBuilders.nested("attr_agg", "attrValueList");
        // 外层聚合出属性id，terms是聚合名称，field-聚合字段
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrId_agg").field("attrValueList.productAttributeId");
        nestedAgg.subAggregation(attrIdAgg); // 添加子聚合
        // 聚合出属性名
        attrIdAgg.subAggregation(AggregationBuilders.terms("attrName").field("attrValueList.name"));
        // 聚合出属性值
        attrIdAgg.subAggregation(AggregationBuilders.terms("attrValue").field("attrValueList.value"));
        sourceBuilder.aggregation(nestedAgg);

        //5.2 品牌聚合
        TermsAggregationBuilder BrandAgg = AggregationBuilders.terms("brandId").field("brandId")
                .subAggregation(AggregationBuilders.terms("brandName").field("brandName"));
        sourceBuilder.aggregation(BrandAgg);

        // 5.3分类聚合
        TermsAggregationBuilder categoryAgg = AggregationBuilders.terms("categoryId").field("productCategoryId")
                .subAggregation(AggregationBuilders.terms("categoryName").field("productCategoryName"));
        sourceBuilder.aggregation(categoryAgg);

        return sourceBuilder.toString();
    }

    public static void main(String[] args) {
        SearchParamVO searchParamVO = new SearchParamVO();
        searchParamVO.setKeyword("xxxx");
        searchParamVO.setBrand(new String[]{"7"});
        searchParamVO.setCatelog3(new String[]{"225"});
        searchParamVO.setOrder("1:desc");
        searchParamVO.setPriceFrom(2000);
        searchParamVO.setPriceTo(5000);
        System.out.println(new SearchServiceImpl().buildDslQuery(searchParamVO));
    }

}
